/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { Ref, nextTick, ref } from 'vue';
import {
    DataGridHeaderCell,
    HeaderCellStatus,
    UseColumn,
    UseDataView,
    UseColumnFilter,
    UseFilterHistory,
    UseSort,
    UseVirtualScroll,
    UseFilter
} from '../../composition/types';
import { DataGridProps, SortType } from '../../data-grid.props';
import getColumnFilterContainer from '../filter/column-filter-container.component';

export default function (
    props: DataGridProps,
    gridContentRef: Ref<any>,
    leftFixedGridContentRef: Ref<any>,
    rightFixedGridContentRef: Ref<any>,
    useColumnComposition: UseColumn,
    useDataViewComposition: UseDataView,
    useColumnFilterComposition: UseColumnFilter,
    useFilterComposition: UseFilter,
    useFilterHistoryComposition: UseFilterHistory,
    useSorterComposition: UseSort,
    useVirtualScrollComposition: UseVirtualScroll
) {
    function columnHandlerClass(headerCell: DataGridHeaderCell) {
        const headerStatus = headerCell.status;
        const shouldShowColumnHandlerIcon =
            (headerStatus & HeaderCellStatus.filtered) === HeaderCellStatus.filtered ||
            (headerStatus & HeaderCellStatus.sorted) === HeaderCellStatus.sorted ||
            headerCell.showPopover;
        const classObject = {
            'fv-column-handler': true,
            'fv-column-handler-active': shouldShowColumnHandlerIcon
        } as Record<string, boolean>;
        return classObject;
    }

    function shouldShowSortableOnly(headerCell: DataGridHeaderCell) {
        return (
            (headerCell.status & HeaderCellStatus.sortable) === HeaderCellStatus.sortable &&
            (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.none &&
            (headerCell.status & HeaderCellStatus.sorted) === HeaderCellStatus.none
        );
    }

    function shouldShowAscendingOnly(headerCell: DataGridHeaderCell) {
        return (
            (headerCell.status & HeaderCellStatus.sortable) === HeaderCellStatus.sortable &&
            (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.none &&
            (headerCell.status & HeaderCellStatus.sorted) === HeaderCellStatus.sorted &&
            (headerCell.status & HeaderCellStatus.ascending) === HeaderCellStatus.ascending
        );
    }

    function shouldShowDescendingOnly(headerCell: DataGridHeaderCell) {
        return (
            (headerCell.status & HeaderCellStatus.sortable) === HeaderCellStatus.sortable &&
            (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.none &&
            (headerCell.status & HeaderCellStatus.sorted) === HeaderCellStatus.sorted &&
            (headerCell.status & HeaderCellStatus.descending) === HeaderCellStatus.descending
        );
    }

    function shouldShowFilterableOnly(headerCell: DataGridHeaderCell) {
        return (
            (headerCell.status & HeaderCellStatus.sortable) === HeaderCellStatus.none &&
            (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.filterable &&
            (headerCell.status & HeaderCellStatus.sorted) === HeaderCellStatus.none
        );
    }

    function shouldShowFilterableAndSortable(headerCell: DataGridHeaderCell) {
        return (
            (headerCell.status & HeaderCellStatus.sortable) === HeaderCellStatus.sortable &&
            (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.filterable &&
            (headerCell.status & HeaderCellStatus.sorted) === HeaderCellStatus.none
        );
    }

    function shouldShowFilterAndAcending(headerCell: DataGridHeaderCell) {
        return (
            (headerCell.status & HeaderCellStatus.sortable) === HeaderCellStatus.sortable &&
            (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.filterable &&
            (headerCell.status & HeaderCellStatus.sorted) === HeaderCellStatus.sorted &&
            (headerCell.status & HeaderCellStatus.ascending) === HeaderCellStatus.ascending
        );
    }

    function shouldShowFilterAndDescending(headerCell: DataGridHeaderCell) {
        return (
            (headerCell.status & HeaderCellStatus.sortable) === HeaderCellStatus.sortable &&
            (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.filterable &&
            (headerCell.status & HeaderCellStatus.sorted) === HeaderCellStatus.sorted &&
            (headerCell.status & HeaderCellStatus.descending) === HeaderCellStatus.descending
        );
    }

    const getHeaderOperationIconClass = function (headerCell: DataGridHeaderCell) {
        const classObject = {
            'f-icon': true,
            'f-icon-col-defaultsort': shouldShowSortableOnly(headerCell),
            'f-icon-col-ascending': shouldShowAscendingOnly(headerCell),
            'f-icon-col-descending': shouldShowDescendingOnly(headerCell),
            'f-icon-col-filter': shouldShowFilterableOnly(headerCell),
            'f-icon-col-defaultfilterandsort': shouldShowFilterableAndSortable(headerCell),
            'f-icon-col-filterandascending': shouldShowFilterAndAcending(headerCell),
            'f-icon-col-filteranddescending': shouldShowFilterAndDescending(headerCell)
        } as Record<string, boolean>;
        return classObject;
    };

    const headerCellClickStatusMap = new Map<number, number>([
        [HeaderCellStatus.sortable, HeaderCellStatus.sortable | HeaderCellStatus.sorted | HeaderCellStatus.ascending],
        [
            HeaderCellStatus.sortable | HeaderCellStatus.sorted | HeaderCellStatus.ascending,
            HeaderCellStatus.sortable | HeaderCellStatus.sorted | HeaderCellStatus.descending
        ],
        [HeaderCellStatus.sortable | HeaderCellStatus.sorted | HeaderCellStatus.descending, HeaderCellStatus.sortable]
    ]);

    const { renderFilterContainer } = getColumnFilterContainer(
        useColumnComposition,
        useDataViewComposition,
        useColumnFilterComposition,
        useFilterComposition,
        useFilterHistoryComposition,
        useSorterComposition,
        useVirtualScrollComposition
    );

    const popoverRef = ref<any>();

    function resetPopoverFilterPanel(currentHeaderCell: DataGridHeaderCell, headerCells: DataGridHeaderCell[]) {
        headerCells
            .filter((headerCell: DataGridHeaderCell) => headerCell !== currentHeaderCell && headerCell.showPopover)
            .forEach((shownPopoverCell: DataGridHeaderCell) => {
                shownPopoverCell.showPopover = false;
            });
    }

    function renderPopoverFilterPanel(headerCell: DataGridHeaderCell) {
        return (
            <f-popover
                ref={popoverRef}
                class="fv-column-handler-popover"
                host={gridContentRef.value}
                z-index={0}
                right-boundary={rightFixedGridContentRef.value}
                offsetX={useVirtualScrollComposition.offsetX}
                visible={true}
                onHidden={() => {
                    headerCell.showPopover = false;
                }}>
                {renderFilterContainer(headerCell)}
            </f-popover>
        );
    }

    async function togglePopoverFilterPanel($event: MouseEvent, currentHeaderCell: DataGridHeaderCell) {
        currentHeaderCell.showPopover = !currentHeaderCell.showPopover;
        await nextTick();
        const popoverInstance = popoverRef.value;
        if (popoverInstance) {
            popoverInstance.show($event.target);
        }
    }

    function updateSortStatus(headerCell: DataGridHeaderCell) {
        const headerStatus = headerCell.status;
        const sortable = (headerStatus & HeaderCellStatus.sortable) === HeaderCellStatus.sortable;
        const sortableOnly = sortable && (headerStatus & HeaderCellStatus.filterable) === HeaderCellStatus.none;
        if (sortableOnly && headerCellClickStatusMap.has(headerStatus)) {
            const nextStatus = headerCellClickStatusMap.get(headerStatus) as HeaderCellStatus;
            const hasSorted = (nextStatus & HeaderCellStatus.sorted) === HeaderCellStatus.sorted;
            const ascending = (nextStatus & HeaderCellStatus.ascending) === HeaderCellStatus.ascending;
            const decending = (nextStatus & HeaderCellStatus.descending) === HeaderCellStatus.descending;
            const targetColumn = headerCell.column;
            if (targetColumn) {
                targetColumn.sort = ascending ? 'asc' : decending ? 'desc' : 'none';
                targetColumn.sortOrder = hasSorted ? targetColumn.sortOrder : 0;
                headerCell.status = nextStatus;
                useColumnComposition.applyColumnSorter(useDataViewComposition, useSorterComposition);
                useVirtualScrollComposition.reCalculateVisualDataRows();
            }
        }
    }

    function onClickColumnHandler($event: MouseEvent, headerCell: DataGridHeaderCell, headerCells: DataGridHeaderCell[]) {
        updateSortStatus(headerCell);
        resetPopoverFilterPanel(headerCell, headerCells);
        const filerable = (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.filterable;
        if (filerable) {
            togglePopoverFilterPanel($event, headerCell);
        }
    }

    function renderHeaderCellHandler(headerCell: DataGridHeaderCell, headerCellIndex: number, headerCells: DataGridHeaderCell[]) {
        const cellHanderNodes = [
            <span
                class={columnHandlerClass(headerCell)}
                onClick={(payload: MouseEvent) => onClickColumnHandler(payload, headerCell, headerCells)}>
                <i class={getHeaderOperationIconClass(headerCell)}></i>
                {headerCell && headerCell.column && headerCell.sortType !== 'none' && (headerCell.column.sortOrder || '')}
                {headerCell.showPopover && renderPopoverFilterPanel(headerCell)}
            </span>
        ];
        return cellHanderNodes;
    }

    return { renderHeaderCellHandler };
}
